package com.bear.newsset.adapter;

import android.annotation.SuppressLint;
import androidx.annotation.IdRes;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;

import com.bear.newsset.util.LogUtils;
import com.bumptech.glide.RequestManager;
import com.jcodecraeer.xrecyclerview.XRecyclerView;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 多选版RecyclerView适配器
 * @param <E>
 */
public abstract class BaseMultiselectXRecyclerViewAdapter
        <E extends BaseXRecyclerViewAdapter.BaseXrvEntity> extends BaseXRecyclerViewAdapter<E> {

    /**
     * 多选显示的位置
     */
    public enum MultiselectGravity {
        LEFT, RIGHT
    }

    public interface OnItemClickMultiselectListener {
        void onItemClick(@NonNull XRecyclerView.Adapter<?> adapter,
                         @Nullable View v, int position, @IdRes int id);
    }

    public interface OnItemCheckedChangeListener {
        void onChange(View v, boolean isChecked, int position);
    }

    public interface OnChangeMultiselectModeListener {
        void oChange(XRecyclerView.Adapter<?> adapter, boolean enable);
    }

    public interface OnMultiSizeChangeListener {
        void onChange(int size);
    }

    private BaseMultiselectXRecyclerViewAdapter mThis;
    private ViewGroup mViewGroup;
    private Map<View, Boolean> multiLayoutMap = new LinkedHashMap<>();
    private MultiselectGravity currentGravity = MultiselectGravity.LEFT;
    private boolean isEnableMultiselectMode, isSelectAll;
    private AtomicInteger atoId = new AtomicInteger();

    private OnItemClickMultiselectListener mOnClickMultiselectListener;
    public OnItemCheckedChangeListener mOnItemCheckedChangeListener;
    private OnChangeMultiselectModeListener mOnChangeMultiselectModeListener;
    private OnMultiSizeChangeListener mOnMultiSizeChangeListener;

    public BaseMultiselectXRecyclerViewAdapter(@NonNull List<E> mDataList) {
        super(mDataList);
        mThis = this;
    }

    public BaseMultiselectXRecyclerViewAdapter(@Nullable RequestManager mGlide,
                                               @NonNull List<E> mDataList) {
        super(mGlide, mDataList);
        mThis = this;
    }

    /**
     * 创建带多选的ItemView
     *
     * @see #onCreateViewHolder(ViewGroup, int)
     * 创建Holder的时候需要传入一个View，可以通过它进行创建。
     *
     * @param viewGroup             {@link ViewGroup}
     * @param itemView              主要展示的View
     * @param multiselectView       自定义的多选View
     * @param gravity               多选View显示的位置
     * @return                      返回创建好的View
     */
    @SuppressLint("ClickableViewAccessibility")
    public View createMultiselectItemView(@NonNull ViewGroup viewGroup,
                                          @NonNull View itemView,
                                          @NonNull View multiselectView,
                                          @NonNull MultiselectGravity gravity) {
        //多选View的Id
        int multiselectId = 1000000 + atoId.getAndIncrement();
        int match = ViewGroup.LayoutParams.MATCH_PARENT;

        LinearLayout superLayout = new LinearLayout( viewGroup.getContext() );
        LinearLayout multiLayout = new LinearLayout( viewGroup.getContext() );
        LinearLayout itemLayout = new LinearLayout( viewGroup.getContext() );
        LinearLayout.LayoutParams superLP, itemLP, multiselectLP;

        mViewGroup = viewGroup;
        superLP = new LinearLayout.LayoutParams( match, ViewGroup.LayoutParams.WRAP_CONTENT );

        multiselectLP = new LinearLayout.LayoutParams( 0, match );
        itemLP = new LinearLayout.LayoutParams( 0, match );

        /* 设置权重 */
        multiselectLP.weight = 1;
        itemLP.weight = 9;

        //设置父布局参数
        superLayout.setLayoutParams( superLP );
        superLayout.setOrientation(LinearLayout.HORIZONTAL);

        //添加子布局
        currentGravity = gravity;
        switch ( gravity ) {
            case RIGHT:
                superLayout.addView( itemLayout );      //itemView在左边
                superLayout.addView( multiLayout );     //多选View在右边
                break;
            default://默认为LEFT
                superLayout.addView( multiLayout );     //多选View在左边
                superLayout.addView( itemLayout );      //itemView在右边
                break;
        }

        //设置ItemView布局参数
        itemLayout.setLayoutParams( itemLP );
        itemLayout.addView( itemView );

        //设置多选View布局参数
        multiLayout.setLayoutParams( multiselectLP );
        multiLayout.setId( multiselectId );
        multiLayout.setOrientation(LinearLayout.HORIZONTAL);
        multiLayout.addView( multiselectView );
        multiLayout.setVisibility( isEnableMultiselectMode ? View.VISIBLE : View.GONE );

        //多选布局点击事件监听器
        multiLayout.setOnClickListener(v -> {
            View item = getMultiselectView( (LinearLayout) v );
            //当前布局的下标
            int position = getMultiselectLayoutPosition( v );
            //取反设置当前选中的多选View
            boolean isChecked = !getItemMultiselectStatus(v);
            //修改多选状态
            setItemMultiselectStatus( v, isChecked, true );
            //回调点击事件监听器
            if( mOnClickMultiselectListener != null ) {
                mOnClickMultiselectListener.onItemClick(mThis, item, position, v.getId());
            }
        });

        //添加多选View的id到列表中
        setItemMultiselectStatusForMultiselectItemView( superLayout, false );
        return superLayout;
    }

    /**
     * 设置指定Item的多选状态
     * @param multiLayout   多选View的父布局Id
     * @param status        状态
     * @param isNotify      是否通知{@link OnItemCheckedChangeListener}
     */
    private void setItemMultiselectStatus(View multiLayout, boolean status, boolean isNotify) {
        //保存Item以及状态
        multiLayoutMap.put(multiLayout, status);
        //更新可能存在未显示多选View的Item
        if( isSelectAll ) setItemMultiselectStatusAll( true );
        LogUtils.d("setItemMultiselectStatus",
                "id:" + multiLayout.getId() + "  status:" + status + "  isNotify:" + isNotify);
        //状态改变监听器
        if( isNotify && mOnItemCheckedChangeListener != null ) {
            View multiView = getMultiselectView( (LinearLayout) multiLayout );
            int position = getMultiselectLayoutPosition( multiView );
            mOnItemCheckedChangeListener.onChange(multiView, status, position);
        }
        if( mOnMultiSizeChangeListener != null ) mOnMultiSizeChangeListener.onChange( getSelectCount() );
    }

    public void setItemMultiselectStatus(View v, boolean status) {
        setItemMultiselectStatus(v, status, false);
    }

    public void setItemMultiselectStatusAll(boolean status) {
        isSelectAll = status;
        for (View v : multiLayoutMap.keySet()) {
            if( status == multiLayoutMap.get( v ) ) continue;
            setItemMultiselectStatus( v, status, true );
        }
    }

    /**
     * 设置指定Item的多选状态
     * 通过 {@link #createMultiselectItemView(ViewGroup, View, View, MultiselectGravity)} 创建的View
     * 进行设置
     * @param v        {@link #createMultiselectItemView(ViewGroup, View, View, MultiselectGravity)}
     * @param status   多选状态
     */
    public void setItemMultiselectStatusForMultiselectItemView(View v, boolean status) {
        LinearLayout superLayout = (LinearLayout) v;
        int index = currentGravity == MultiselectGravity.LEFT ? 0 : 1;
        setItemMultiselectStatus( superLayout.getChildAt( index ) , status );
    }

    /**
     * 切换Item的多选状态
     * @param multiselectLayout     多选View的父布局
     */
    public void switchItemMultiselectStatus(LinearLayout multiselectLayout) {
        Boolean getBool = multiLayoutMap.get(multiselectLayout);
        if( getBool == null ) return;
        //切换多选状态，同时通知状态改变监听器
        setItemMultiselectStatus(multiselectLayout, !getBool, true);
    }
    public void switchItemMultiselectStatus(int position) {
        switchItemMultiselectStatus( getMultiselectLayout( position ) );
    }

    /**
     * 移除指定Item的多选状态
     * @param position    当前Item的下标
     */
    public void removeItemMultiselectStatus(int position) {
        removeItemMultiselectStatus( getMultiselectLayout( position ) );
    }
    public void removeItemMultiselectStatus(@Nullable LinearLayout multiLayout) {
        if( multiLayout == null ) return;
        multiLayoutMap.remove( multiLayout );
        if( mOnMultiSizeChangeListener != null ) mOnMultiSizeChangeListener.onChange( getSelectCount() );
    }

    /**
     * 移除选中的Item多选状态
     */
    private void removeSelectItemMultiselectStatus() {
        removeItemMultiselectStatusAll( 1 );
    }

    /**
     * 移除未选中的Item多选状态
     */
    private void removeNotSelectItemMultiselectStatus() {
        removeItemMultiselectStatusAll( 0 );
    }

    /**
     * 移除所有Item多选状态
     */
    private void removeItemMultiselectStatusAll() {
        removeItemMultiselectStatusAll( -1 );
    }

    /**
     * 移除Item多选的所有状态，根据type决定移除类型
     * @param type      -1：全部，0：未选中，1：已选中
     */
    private void removeItemMultiselectStatusAll(@IntRange(from = -1, to = 1) int type) {
        List<Boolean> all = getItemMultiselectStatusAll();
        for (int i = 0; i < all.size(); i++) {
            boolean isSelect = all.get( i );
            LinearLayout v = getMultiselectLayout( i );
            switch ( type ) {
                case -1:    //全部移除
                    removeItemMultiselectStatus( v );
                    break;
                case 0:     //只移除未选中
                    if( !isSelect ) removeItemMultiselectStatus( v );
                    break;
                case 1:     //只移除已选中
                    if( isSelect ) removeItemMultiselectStatus( v );
                    break;
            }
        }
    }

    /**
     * 获取多选View的父布局
     * 传入的多选view都会被{@link LinearLayout}包裹，所有本类中的所有多选操作均为对它操作
     * {@link LinkedHashMap} 保证在循环时不会错乱
     * @param position      位置
     * @return              View
     */
    @Nullable
    public LinearLayout getMultiselectLayout(int position) {
        int i = 0;
        for( View v : multiLayoutMap.keySet() ) {
            if( i == position ) return (LinearLayout) v;
            i++;
        }
        return null;
    }
    @Nullable
    public LinearLayout getMultiselectLayoutForId(@IdRes int id) {
        return getMultiselectLayout( getMultiselectLayoutPosition( id ));
    }

    /**
     * 根据id获取多选View
     * @param id    id
     * @return      View
     */
    @Nullable
    public View getMultiselectView(@IdRes int id) {
        if( mViewGroup == null ) return null;
        //查找View需要先查找父布局，父布局需要下标
        return getMultiselectView( getMultiselectLayoutForId( id ) );
    }
    @Nullable
    public View getMultiselectView(@Nullable LinearLayout multiselectLayout) {
        return multiselectLayout == null ? null : multiselectLayout.getChildAt( 0 );
    }

    /**
     * 当前多选View父布局的下标
     * @param multiLayout     查找的父布局
     * @return                返回位置。找不到返回0
     */
    public int getMultiselectLayoutPosition(View multiLayout) {
        if( multiLayout == null ) return 0;
        return getMultiselectLayoutPosition( multiLayout.getId() );
    }
    public int getMultiselectLayoutPosition(@IdRes int id) {
        int i = 0;
        for( View v : multiLayoutMap.keySet() ) {
            if( v == null ) continue;
            if( v.getId() == id ) return i;
            i++;
        }
        return 0;
    }

    /**
     * 获取选中的数量
     * @return      数量
     */
    public int getSelectCount() {
        int count = 0;
        for (Boolean b : getItemMultiselectStatusAll()) {
            if( b ) count++;
        }
        return count;
    }

    /**
     * 获取指定View id的多选状态
     * @param id    查询的id
     * @return      状态
     */
    public boolean getItemMultiselectStatus(@IdRes int id) {
        return getItemMultiselectStatus( getMultiselectLayoutForId( id ) );
    }

    /**
     * 获取指定View的多选状态
     * @param v     查询的View
     * @return      状态
     */
    public boolean getItemMultiselectStatus(@Nullable View v) {
        if( v == null ) return false;
        return multiLayoutMap.put(v, false);
    }

    /**
     * 获取所有Item的多选状态
     * @return      状态列表
     */
    public List<Boolean> getItemMultiselectStatusAll() {
        return new ArrayList<>( multiLayoutMap.values() );
    }

    /**
     * 设置是否启用多选模式
     * @param enable    是否启用
     */
    public void setEnableMultiselectMode(boolean enable) {
        isEnableMultiselectMode = enable;
        for (int i = 0; i < multiLayoutMap.size(); i++) {
            //通过多选View的父布局控制隐藏和显示
            View v = getMultiselectLayout( i );
            if( v == null || (v.getVisibility() == View.VISIBLE && enable) ) continue;
            v.setVisibility( enable ? View.VISIBLE : View.GONE );
        }
        //发生改变后回调监听器
        if( mOnChangeMultiselectModeListener != null ) {
            mOnChangeMultiselectModeListener.oChange(this, enable);
        }
    }

    /**
     * 开启/关闭多选模式
     */
    public void switchMultiselectMode() {
        setEnableMultiselectMode( !isEnableMultiselectMode );
    }

    /**
     * 多选模式启用状态
     * @return      是否启用
     */
    public boolean isEnableMultiselectMode() {
        return isEnableMultiselectMode;
    }

    /**
     * 设置多选模式发生改变时事件监听器
     * @param listener      监听器
     */
    public void setOnChangeMultiselectModeListener(OnChangeMultiselectModeListener listener) {
        mOnChangeMultiselectModeListener = listener;
    }

    /**
     * 设置Item的多选操作点击事件监听器
     * @param listener      监听器
     */
    public void setOnItemClickMultiselectListener(OnItemClickMultiselectListener listener) {
        mOnClickMultiselectListener = listener;
    }

    public void setOnCheckedChangeListener(OnItemCheckedChangeListener listener) {
        this.mOnItemCheckedChangeListener = listener;
    }

    /**
     * 设置切换发生改变事件监听器
     * @param listener      监听器
     */
    public void setOnMultiSizeChangeListener(OnMultiSizeChangeListener listener) {
        this.mOnMultiSizeChangeListener = listener;
    }

    @Override
    public int setUpResources() {
        return 0;
    }

    @Override
    public int setDownResources() {
        return 0;
    }
}